package cn.flant.exec;

import java.util.concurrent.TimeUnit;

public class CircularExecutor implements Runnable {
	private Runner runner = new Runner();
	private boolean isRunning = false;
	private Thread thread = null;
	private Runnable runnable = null;
	private String name = null;
	private long circularGap = -1;
	private int maxExecuteCount = 0;
	private int executeCount = 0;

	public CircularExecutor() {
		this(null);
	}

	public CircularExecutor(Runnable runnable) {
		this(runnable, null);
	}

	public CircularExecutor(Runnable runnable, String name) {
		this(runnable, name, -1, null);
	}

	public CircularExecutor(Runnable runnable, long circularGap, TimeUnit unit) {
		this(runnable, null, circularGap, unit);
	}

	public CircularExecutor(Runnable runnable, String name, long circularGap, TimeUnit unit) {
		if (runnable == null) {
			runnable = this;
		}
		this.runnable = runnable;
		this.name = name;
		setCircularGap(circularGap, unit);
	}

	public long getCircularGap() {
		return circularGap;
	}

	public void setCircularGap(long circularGap, TimeUnit unit) {
		if (unit == null) {
			this.circularGap = circularGap;
		} else {
			this.circularGap = TimeUnit.MILLISECONDS.convert(circularGap, unit);
		}
	}

	public int getMaxExecuteCount() {
		return maxExecuteCount;
	}

	public void setMaxExecuteCount(int maxExecuteCount) {
		this.maxExecuteCount = maxExecuteCount;
	}

	public int getExecuteCount() {
		return executeCount;
	}

	public synchronized void startup() {
		if (isRunning) {
			return;
		}
		isRunning = true;
		if (name == null) {
			thread = new Thread(runner);
		} else {
			thread = new Thread(runner, name);
		}
		thread.setDaemon(true);
		thread.start();
	}

	public synchronized void shutdown() {
		if (!isRunning) {
			return;
		}
		isRunning = false;
		if (thread != null) {
			thread.interrupt();
			thread = null;
		}
	}

	public boolean isRunning() {
		return isRunning;
	}

	public void run() {
		maxExecuteCount = 1;
	}

	private class Runner implements Runnable {
		public void run() {
			while (isRunning) {
				try {
					runnable.run();
				} catch (Throwable e) {
				}
				executeCount++;
				if (maxExecuteCount > 0 && executeCount == maxExecuteCount) {
					shutdown();
					break;
				}
				if (circularGap > 0 && isRunning) {
					try {
						Thread.sleep(circularGap);
					} catch (InterruptedException e) {
					}
				}
			}
		}
	}

}
